package com.jo.util;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射的工具类
 * @author Jo
 * @date 2018/1/25
 */
@Slf4j
public class ReflectionUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class);

    public static void injectField(Field field, Object obj, Object fieldValue){

        field.setAccessible(true);
        try {
            field.set(obj, fieldValue);
        } catch (IllegalAccessException e) {
            LOGGER.error("注入field失败");
        }
    }

    public static Object methodInvoke(Method method, Object[] args, Object target){
        method.setAccessible(true);
        try {
            return method.invoke(target, args);
        } catch (IllegalAccessException e) {
            log.error("method访问出错");
        } catch (InvocationTargetException e) {
            log.error("method调用出错");
        }
        return target;
    }

    public static Object constructorNewInstance(Constructor<?> constructor, Object[] args){
        try {
            return constructor.newInstance(args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static Object constructorNewInstance(Class<?> clazz, Object[] args){
        Constructor<?>[] constructors = clazz.getConstructors();
        if (constructors.length == 1){
            return constructorNewInstance(constructors[0], args);
        }

        return null;
    }

    public static void doWithMethod(Class<?> clazz, MethodCallback methodCallback){
        for (Method method : clazz.getDeclaredMethods()) {
            method.setAccessible(true);
            methodCallback.doWith(method);
        }
    }

    public static void doWithField(Class<?> clazz, FieldCallback fieldCallback){
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            fieldCallback.doWith(field);
        }
    }

    public interface MethodCallback{
        void doWith(Method method);
    }

    public interface FieldCallback{
        void doWith(Field field);
    }
}
